package com.central.apps.common.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.central.apps.common.constant.ProjectPlanConstant;
import com.central.apps.entity.MpxjBean;
import com.central.apps.entity.TaskBean;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import net.sf.mpxj.*;
import net.sf.mpxj.mpp.MPPReader;
import net.sf.mpxj.mpx.MPXReader;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hpsf.Variant;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 项目计划工具类
 *
 * @author 李大超
 * @date 2022/8/16
 */
public class ProjectPlanUtils {

    /**
     * 读取项目文件
     *
     * @author 李大超
     * @date 2022/8/16
     * @param fileName 文件名 绝对路径
     * @return ProjectFile
     * @throws FileNotFoundException
     */
    private static ProjectFile readProject(String fileName)
            throws FileNotFoundException {
        InputStream is = new BufferedInputStream(new FileInputStream(fileName));
        // 下面需要重复使用输入流，所以重新包装并设置重置标记
        is.mark(0);

        ProjectFile mpx = null;
        try {
            mpx = new MPXReader().read(is);
        } catch (Exception ex) {
            try {
                // 重置输入流
                is.reset();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (mpx == null) {
            try {
                mpx = new MPPReader().read(is);
            } catch (Exception ex) {
                try {
                    // 重置输入流
                    is.reset();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return mpx;
    }

    /**
     * 读取项目文件
     *
     * @author 李大超
     * @date 2022/8/16
     * @param file 文件流
     * @return ProjectFile
     * @throws IOException
     */
    private static ProjectFile readProject(MultipartFile file)
            throws IOException {
        InputStream is =  new BufferedInputStream(file.getInputStream());

        ProjectFile mpp = null;
        try {
            mpp = new MPPReader().read(is);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (null != is) {
                is.close();
            }
        }

        return mpp;
    }

    /**
     * 项目文件--获取任务列表
     *
     * @author 李大超
     * @date 2022/8/16
     * @params fileName 读取.mpp文件路径
     * @return List<TaskBean>
     * @throws FileNotFoundException
     */
    public static List<TaskBean> getTaskList(String fileName) throws FileNotFoundException {
        // 读取项目文件
        ProjectFile proFile = readProject(fileName);

        List<Task> tasks = proFile.getChildTasks();
        List<TaskBean> proTaskList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(tasks)) {
            Task topTask = tasks.get(ProjectPlanConstant.TOP_PARENTID);
            proTaskList = listHierarchy(topTask, ProjectPlanConstant.TOP_PARENTID);
        }
        return proTaskList;
    }

    /**
     * 项目文件--获取任务列表
     *
     * @author 李大超
     * @date 2022/8/16
     * @params file 文件
     * @return List<TaskBean>
     * @throws FileNotFoundException
     */
    public static List<TaskBean> getTaskList(MultipartFile file) throws IOException {
        // 读取项目文件
        ProjectFile proFile = readProject(file);

        List<Task> tasks = proFile.getChildTasks();
        List<TaskBean> proTaskList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(tasks)) {
            Task topTask = tasks.get(ProjectPlanConstant.TOP_PARENTID);
            proTaskList = listHierarchy(topTask, ProjectPlanConstant.TOP_PARENTID);
        }
        return proTaskList;
    }

    /**
     * 项目文件--获取任务列表
     *
     * @author 李大超
     * @date 2022/8/16
     * @params fileName 读取.mpp文件路径
     * @return List<TaskBean>
     * @throws FileNotFoundException
     */
    public static MpxjBean getMpxjBean(MultipartFile file) throws IOException {
        InputStream is = file.getInputStream();
        MpxjBean mpxjBean = JSONObject.parseObject(is, MpxjBean.class, Feature.values());
        is.close();
        return mpxjBean;
    }

    /**
     * 获取任务的子任务
     *
     * @params parentTask 顶层任务
     * @param parentId 父任务Id
     * @author 李大超
     * @date 2022/8/16
     * @return List<TaskBean>
     */

    private static List<TaskBean> listHierarchy(Task parentTask, int parentId) {
        List<Task> childTasks = parentTask.getChildTasks();
        List<TaskBean> proTaskList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(childTasks)) {
            for (Task childTask : childTasks) {
                proTaskList.add(getTaskBean(childTask, parentId));
                proTaskList.addAll(listHierarchy(childTask, childTask.getID()));
            }
        }
        return proTaskList;
    }

    /**
     * 获取任务的具体字段
     *
     * @author 李大超
     * @date 2022/8/16
     * @params task 任务
     * @params parentId 父类Id
     * @return TaskBean
     */
    private static TaskBean getTaskBean(Task task, Integer parentId) {
        TaskBean taskBean = new TaskBean();
        taskBean.setRecordId(task.getID().toString());
        taskBean.setUniqueId(task.getUniqueID().toString());
        taskBean.setParentId(parentId);
        taskBean.setName(task.getName());
        taskBean.setDescription(task.getNotes());
        String manager = task.getText(1);
        if (StringUtils.isEmpty(manager)) {
            manager = "";
        }
        taskBean.setManager(manager);
        taskBean.setDuration(task.getDuration().getDuration());
        taskBean.setDurationTimeUnit(task.getDuration().getUnits().getName());
        taskBean.setStartTime(task.getStart());
        taskBean.setFinishTime(task.getFinish());
        taskBean.setPercentageComplete(task.getPercentageComplete());
        taskBean.setLevel(task.getOutlineLevel());
        taskBean.setResources(listTaskRes(task));
        taskBean.setHasChild(task.hasChildTasks());

        List<String> predecessorList = new ArrayList<>();

        List<Relation> predecessors = task.getPredecessors();
        if (CollectionUtils.isNotEmpty(predecessors)) {
            for (Relation relation : predecessors) {
                Task tragetTask = relation.getTargetTask();
                Integer targetTaskRecordId = tragetTask.getID();
                Integer targetTaskUniqueId = tragetTask.getUniqueID();
                // SS:开始开始/FS:结束开始
                String mType = relation.getType().toString();
                // 10.0d//0.0d//-35.0d
                String mLag = relation.getLag().toString();

//                String predecessor = targetTaskRecordId + ":" + targetTaskUniqueId + ":" + m_type + ":" + m_lag;
                StringBuilder predecessor = new StringBuilder();
                predecessor.append(targetTaskRecordId);
                if (!"0.0d".equals(mLag)) {
                    predecessor.append(":");
                    // jQueryGantt Only the finish-to-start dependency type is supported
                    predecessor.append(mLag.replace(".0d", ""));
                }

                predecessorList.add(predecessor.toString());
            }
        }
        taskBean.setPredecessors(listToString(predecessorList));
        return taskBean;
    }

    /**
     * List 转为 String
     *
     * @author 李大超
     * @date 2022/8/16
     * @params List<String> 对象集合
     * @return String
     */
    public static String listToString(List<String> list) {
        StringBuilder sb = new StringBuilder();
        if (CollectionUtils.isNotEmpty(list)) {
            for (int i = 0; i < list.size(); i++) {
                sb.append(list.get(i));
                if (i < list.size() - 1) {
                    sb.append(",");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 获取任务中的资源
     *
     * @author 李大超
     * @date 2022/8/16
     * @param task 任务
     * @return List<String>
     */
    private static List<String> listTaskRes(Task task) {
        List<String> resourceList = new ArrayList<>();
        // 获取任务资源列表
        List<ResourceAssignment> assignments = task.getResourceAssignments();
        for (ResourceAssignment resourceAssignment : assignments) {
            Resource resource = resourceAssignment.getResource();
            if (resource != null) {
                resourceList.add(resource.getName());
            }
        }
        return resourceList;
    }

    /**
     * 读取文件
     *
     * @author 李大超
     * @date 2022/8/16
     * @param fileName 文件名称
     */
//    private static String readUtf8File(String fileName) {
//        // 以utf-8编码读取文件：
//        FileInputStream fis = null;
//        InputStreamReader isr = null;
//        StringBuilder fileContent = new StringBuilder();
//
//        try {
//            fis = new FileInputStream(fileName);
//            isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
//            BufferedReader br = new BufferedReader(isr);
//            String line = null;
//            while ((line = br.readLine()) != null) {
//                fileContent.append(line);
//                // 补上换行符
//                fileContent.append("\r\n");
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                assert isr != null;
//                isr.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//
//        return fileContent.toString();
//    }

    /**
     * 写文件
     *
     * @author 李大超
     * @date 2022/8/16
     * @param fileName 文件名称
     */
    public static void writeUtf8File(String fileName, char[] fileContent) {
        // java中文件操作体现了设计模式中的装饰者模式, 以UTF-8编码写入文件
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        try {
            fos = new FileOutputStream(fileName);
            osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
            osw.write(fileContent);
            osw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fos != null;
                fos.close();
                assert osw != null;
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建mpp文件
     *
     * @param taskBeanList 任务列表
     * @throws Exception
     *
     */
    public static void createMppFile(List<TaskBean> taskBeanList, String filePath) throws Exception {
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
        }
        if (CollectionUtils.isNotEmpty(taskBeanList)) {
            ActiveXComponent app = null;
            try {
                app = new ActiveXComponent("MSProject.Application");
                app.setProperty("Visible", false);
                Dispatch projects = app.getProperty("Projects").toDispatch();
                Dispatch project = Dispatch.call(projects, "Add").toDispatch();//添加一个项目
                Dispatch tasks = Dispatch.get(project, "Tasks").toDispatch();//生成一个task集合
                //生成Task
                TaskBean topTaskBean = getTopTaskBean(taskBeanList);
                createTreeTable(tasks, topTaskBean, ProjectPlanConstant.TOP_LEVEL, taskBeanList);
                //另存为
                Dispatch.invoke(project, "SaveAs", Dispatch.Method, new Object[]{filePath, 0}, new int[1]);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (app != null) {
                    app.invoke("Quit", String.valueOf(new Variant[]{}));
                }
            }
        }
    }

    /**
     * 创建树形结构
     *
     * @param tasks        任务集合
     * @param taskBean     任务Bean
     * @param level        层次
     * @param taskBeanList 任务列表
     */
    private static void createTreeTable(Dispatch tasks, TaskBean taskBean, int level, List<TaskBean> taskBeanList) {
        Dispatch task = Dispatch.call(tasks, "Add").toDispatch();
        setTaskValue(task, taskBean, level);
        List<TaskBean> sonTaskBeanList = getSonTaskBean(taskBeanList, taskBean);
        if (!sonTaskBeanList.isEmpty()) {
            for (TaskBean sonTaskBean : sonTaskBeanList) {
                createTreeTable(tasks, sonTaskBean, level + 1, taskBeanList);
            }
        }
    }

    /**
     * 获取所有的子任务
     *
     * @param taskBeanList   任务列表
     * @param parentTaskBean 父级任务Bean
     * @return
     */
    private static List<TaskBean> getSonTaskBean(List<TaskBean> taskBeanList, TaskBean parentTaskBean) {
        List<TaskBean> sonTaskBeanList = new ArrayList<TaskBean>();
        for (TaskBean taskBean : taskBeanList) {
            if (taskBean.getParentId() == parentTaskBean.getId()) {
                sonTaskBeanList.add(taskBean);
            }
        }
        return sonTaskBeanList;
    }

    /**
     * 获取顶级任务
     *
     * @param taskBeanList 任务列表
     * @return
     */
    private static TaskBean getTopTaskBean(List<TaskBean> taskBeanList) {
        for (TaskBean taskBean : taskBeanList) {
            if (taskBean.getParentId() == ProjectPlanConstant.TOP_PARENTID) {
                return taskBean;
            }
        }
        return null;
    }

    /**
     * 给任务设置属性
     *
     * @param task     任务指针
     * @param taskBean 任务Bean
     * @param level    层次
     */
    private static void setTaskValue(Dispatch task, TaskBean taskBean, int level) {
        Dispatch.put(task, TaskField.ID.name(), taskBean.getId());
        Dispatch.put(task, TaskField.UNIQUE_ID.name(), taskBean.getId());
        Dispatch.put(task, TaskField.NAME.name(), taskBean.getName());
        Dispatch.put(task, TaskField.NOTES.name(), taskBean.getDescription());
        Dispatch.put(task, TaskField.START.name(), taskBean.getStartTime());
        Dispatch.put(task, TaskField.FINISH.name(), taskBean.getFinishTime());
        Dispatch.put(task, TaskField.DURATION.name(),taskBean.getDuration());
        Dispatch.put(task, TaskField.DURATION1_UNITS.name(),taskBean.getDurationTimeUnit());
        Dispatch.put(task, TaskField.PERCENT_COMPLETE.name(), (double)taskBean.getPercentageComplete());
        Dispatch.put(task, TaskField.OUTLINE_LEVEL.name(), level);
        Dispatch.put(task, TaskField.RESOURCE_NAMES.name(), taskBean.getResources());
        Dispatch.put(task, TaskField.PREDECESSORS.name(), taskBean.getPredecessors());
        Dispatch.put(task, TaskField.PARENT_TASK_UNIQUE_ID.name(), taskBean.getParentId());
        Dispatch.put(task, TaskField.TEXT1.name(), taskBean.getManager());
    }

    /**
     * 检查文件类型
     *
     * @author 李大超
     * @date 2022/8/16
     * @param filename 文件名称
     * @return Boolean
     */
    public static Boolean checkFile(String filename){
        //检查文件是否是json/mpp类型文件
        return filename.toLowerCase(Locale.ROOT).endsWith("json") || filename.toLowerCase().endsWith("mpp");
    }
}
